/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package Dao;

import Controle.SitemaControle;
import Modelo.Login;
import Util.PAPUtil;
import java.util.ArrayList;
import java.util.Date;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JOptionPane;
import org.hibernate.*;
import org.hibernate.criterion.*;

/**
 *
 * @author Sergio
 */
public class SistemaDAO implements SitemaControle {

    PAPUtil papUtil = new PAPUtil();
    @Override
    public void addUpObjeto(Object x) {
        SessionFactory ss = HibernateUtil.getSessionFactory();
        Session session = ss.openSession();

        Transaction tr = session.beginTransaction();

        try {
            session.saveOrUpdate(x);
            tr.commit();
        } catch (Exception e) {
            tr.rollback();
            JOptionPane.showMessageDialog(null, "Occoreu o sguinte erro ao tentar salvar os dados: " + e.getMessage(),
                    "Erro", 0);

        } finally {
            session.close();
        }
    }

    @Override
    public ArrayList listar(String x) {
        SessionFactory sf = HibernateUtil.getSessionFactory();
        Session session = sf.openSession();
        Object ccc = null;
        String xxx = x.toString();
        try {
            try {
                ccc = Class.forName(xxx).newInstance();
            } catch (java.lang.InstantiationException | IllegalAccessException ex) {
                Logger.getLogger(SistemaDAO.class.getName()).log(Level.SEVERE, null, ex);
            }
        } catch (ClassNotFoundException ex) {
            Logger.getLogger(SistemaDAO.class.getName()).log(Level.SEVERE, null, ex);
        }

        ArrayList lista = null;

        Criteria c = session.createCriteria(ccc.getClass());

        lista = (ArrayList) c.list();

        return lista;
    }

    @Override
    public void removeObjeto(Object l) {
        SessionFactory ss = HibernateUtil.getSessionFactory();
        Session session = ss.openSession();

        Transaction tr = session.beginTransaction();
        session.delete(l);
        tr.commit();
        session.close();
    }

    /**
     *
     * @param <T>
     * @param x Classe Generica do objeto
     * @param nome Descrição da Condição
     * @param group Array de Strings onde será adicionado os campos do group By
     * @param order Array de Strings onde será adicionado os campos do Order By
     * @param campo Nome do campo do DB a ser pesquisado
     * @param tipoPesq Tipo de Pesquisa 0 - Código igual 1 - Nome Iniciando 2 -
     * Nome Contendo
     * @return Lista de Objetos com o resultado do SQl
     */

    @Override
    public boolean verificaLogin(String usuario, String senha) {
        SessionFactory sf = HibernateUtil.getSessionFactory();
        Session session = sf.openSession();

        Criteria c = session.createCriteria(Login.class);
        c.add(Restrictions.eq("usuario", usuario));
        c.add(Restrictions.eq("senha", senha));

        if (c.list().isEmpty()) {
            return false;
        } else {
            return true;
        }
    }

    @Override
    public ArrayList listaCondicao(String x, String nome, String[] group, String[] order, String campo, int tipoPesq) {
        //nome = nome.toUpperCase(Locale.FRENCH);
        SessionFactory sf = HibernateUtil.getSessionFactory();
        Session session = sf.openSession();

        Object ccc = null;
        String xxx = x.toString();
        try {
            try {
                ccc = Class.forName(x).newInstance();
            } catch (java.lang.InstantiationException | IllegalAccessException ex) {
                Logger.getLogger(SistemaDAO.class.getName()).log(Level.SEVERE, null, ex);
            }
        } catch (ClassNotFoundException ex) {
            Logger.getLogger(SistemaDAO.class.getName()).log(Level.SEVERE, null, ex);
        }

        ArrayList lista = null;

        Criteria c = session.createCriteria(ccc.getClass());
        ProjectionList projList = Projections.projectionList();
        projList = null;

        try {
            switch (tipoPesq) {
                case 0: {//Busca Pelo Id
                    int i = Integer.parseInt(nome);
                    c.add(Restrictions.idEq(i));
                    if (order != null) {
                        for (int v = 0; v < order.length; v++) {
                            c.addOrder(Order.asc(order[v]));
                        }
                    }

                    if (group != null) {
                        for (int v = 0; v < group.length; v++) {
                            projList.add(Projections.property(group[v]));
                        }
                    }

                    if (projList != null) {
                        c.setProjection(projList);
                    }

                    lista = (ArrayList) c.list();

                    if (!lista.isEmpty()) {
                        return lista;
                    }

                    break;

                    //aqui usamos o método add() para adicionar
                    //um critério de busca. Usamos como critério
                    //um objeto do tipo Restrictions e ele nos
                    //formece inumeros outros métodos.
                    //Como a consulta é por id, vamos usar o idEq(),
                    //seria um idEquals. Como vamos retornar apenas um
                    //resultado, devemos indicar com o método uniqueResult().
                }
                case 1: {// Busca varias por seu nome iniciando
                    c.add(Restrictions.like(campo, nome, MatchMode.START).ignoreCase());

                    //O método usado agora é o like(). Precismos informa 3 parâmetros
                    //para ele. O 1° é o atributo (nome) declarado na classe a ser utilizada.
                    //Não confunda com o campo da tabela, deve ser o atributo.   
                    //O 2° parâmetro é o recebido pelo método, que contem o nome usado
                    //o 3° serve para informarmos que queremos localizar todos os
                    //nomes que iniciam com a palavra.

                    if (order != null) {
                        for (int v = 0; v < order.length; v++) {
                            c.addOrder(Order.asc(order[v]));
                        }
                    }

                    if (group != null) {
                        for (int v = 0; v < group.length; v++) {
                            projList.add(Projections.property(group[v]));
                        }
                    }

                    if (projList != null) {
                        c.setProjection(projList);
                    }

                    lista = (ArrayList) c.list();

                    if (!lista.isEmpty()) {
                        return lista;
                    }

                    break;
                }
                case 2: {// Busca varias que possuem o nome contendo
                    c.add(Restrictions.like(campo, nome, MatchMode.ANYWHERE).ignoreCase()); //, 

                    //Desta vez usamos o método like().
                    //Ele possui 3 parâmetros. O 1° e o 2°
                    //já sabemos para que serve, o 3° serve para
                    //informarmos que queremos localizar todos os
                    //nomes que contenham a palavra XXX em qualquer lugar.
                    //e por fim retornamos uma lista.

                    if (order != null) {
                        for (int v = 0; v < order.length; v++) {
                            c.addOrder(Order.asc(order[v]));
                        }
                    }

                    if (group != null) {
                        for (int v = 0; v < group.length; v++) {
                            projList.add(Projections.property(group[v]));
                        }
                    }
                    if (projList != null) {
                        c.setProjection(projList);
                    }

                    lista = (ArrayList) c.list();

                    if (!lista.isEmpty()) {
                        return lista;
                    }

                    break;
                }
                case 3: {
                    int o = Integer.parseInt(nome);
                    c.add(Restrictions.eq(campo, o));
                    //Comparar valores iguais
                    if (order != null) {
                        for (int v = 0; v < order.length; v++) {
                            c.addOrder(Order.asc(order[v]));
                        }
                    }

                    if (group != null) {
                        for (int v = 0; v < group.length; v++) {
                            projList.add(Projections.property(group[v]));
                        }
                    }
                    if (projList != null) {
                        c.setProjection(projList);
                    }

                    if (!c.list().isEmpty()) {
                        lista = (ArrayList) c.list();
                    } else {
                        return null;
                    }

                    if (!lista.isEmpty()) {
                        return lista;
                    }

                    break;
                }
            }

        } catch (NumberFormatException | HibernateException e) {
            session.close();
            JOptionPane.showMessageDialog(null, "Ocorreu o seguinte erro ao pesquisar os dados: " + e.getMessage(),
                    "Erro no pesquisar", 0);
        } finally {
            session.close();
        }

        return lista;
    }
    
    @Override
    public ArrayList listaCondicao(String x, String nome, String[] group, 
        String[] order, String campo, int tipoPesq, Date dataIni, Date dataFinal) {
        dataIni = papUtil.toBancoData(String.valueOf(dataIni));
        dataFinal = papUtil.toBancoData(String.valueOf(dataFinal));
        SessionFactory sf = HibernateUtil.getSessionFactory();
        Session session = sf.openSession();

        Object ccc = null;
        String xxx = x.toString();
        try {
            try {
                ccc = Class.forName(x).newInstance();
            } catch (java.lang.InstantiationException | IllegalAccessException ex) {
                Logger.getLogger(SistemaDAO.class.getName()).log(Level.SEVERE, null, ex);
            }
        } catch (ClassNotFoundException ex) {
            Logger.getLogger(SistemaDAO.class.getName()).log(Level.SEVERE, null, ex);
        }

        ArrayList lista = null;

        Criteria c = session.createCriteria(ccc.getClass());
        ProjectionList projList = Projections.projectionList();
        projList = null;

        try {
            switch (tipoPesq) {
                case 0: {//Busca Pelo Id
                    int i = Integer.parseInt(nome);
                    c.add(Restrictions.idEq(i));
                    c.add(Restrictions.between(campo, dataIni, dataFinal));
                    if (order != null) {
                        for (int v = 0; v < order.length; v++) {
                            c.addOrder(Order.asc(order[v]));
                        }
                    }

                    if (group != null) {
                        for (int v = 0; v < group.length; v++) {
                            projList.add(Projections.property(group[v]));
                        }
                    }

                    if (projList != null) {
                        c.setProjection(projList);
                    }

                    lista = (ArrayList) c.list();

                    if (!lista.isEmpty()) {
                        return lista;
                    }

                    break;

                    //aqui usamos o método add() para adicionar
                    //um critério de busca. Usamos como critério
                    //um objeto do tipo Restrictions e ele nos
                    //formece inumeros outros métodos.
                    //Como a consulta é por id, vamos usar o idEq(),
                    //seria um idEquals. Como vamos retornar apenas um
                    //resultado, devemos indicar com o método uniqueResult().
                }
                case 1: {// Busca varias por seu nome iniciando
                    c.add(Restrictions.like(campo, nome, MatchMode.START).ignoreCase());
                    c.add(Restrictions.between(campo, dataIni, dataFinal));    
                    //O método usado agora é o like(). Precismos informa 3 parâmetros
                    //para ele. O 1° é o atributo (nome) declarado na classe a ser utilizada.
                    //Não confunda com o campo da tabela, deve ser o atributo.   
                    //O 2° parâmetro é o recebido pelo método, que contem o nome usado
                    //o 3° serve para informarmos que queremos localizar todos os
                    //nomes que iniciam com a palavra.

                    if (order != null) {
                        for (int v = 0; v < order.length; v++) {
                            c.addOrder(Order.asc(order[v]));
                        }
                    }

                    if (group != null) {
                        for (int v = 0; v < group.length; v++) {
                            projList.add(Projections.property(group[v]));
                        }
                    }

                    if (projList != null) {
                        c.setProjection(projList);
                    }

                    lista = (ArrayList) c.list();

                    if (!lista.isEmpty()) {
                        return lista;
                    }

                    break;
                }
                case 2: {// Busca varias que possuem o nome contendo
                    c.add(Restrictions.like(campo, nome, MatchMode.ANYWHERE).ignoreCase()); //, 
                    c.add(Restrictions.between(campo, dataIni, dataFinal));
                    //Desta vez usamos o método like().
                    //Ele possui 3 parâmetros. O 1° e o 2°
                    //já sabemos para que serve, o 3° serve para
                    //informarmos que queremos localizar todos os
                    //nomes que contenham a palavra XXX em qualquer lugar.
                    //e por fim retornamos uma lista.

                    if (order != null) {
                        for (int v = 0; v < order.length; v++) {
                            c.addOrder(Order.asc(order[v]));
                        }
                    }

                    if (group != null) {
                        for (int v = 0; v < group.length; v++) {
                            projList.add(Projections.property(group[v]));
                        }
                    }
                    if (projList != null) {
                        c.setProjection(projList);
                    }

                    lista = (ArrayList) c.list();

                    if (!lista.isEmpty()) {
                        return lista;
                    }

                    break;
                }
                case 3: {
                    int o = Integer.parseInt(nome);
                    c.add(Restrictions.eq(campo, o));
                    c.add(Restrictions.between(campo, dataIni, dataFinal));
                    //Comparar valores iguais
                    if (order != null) {
                        for (int v = 0; v < order.length; v++) {
                            c.addOrder(Order.asc(order[v]));
                        }
                    }

                    if (group != null) {
                        for (int v = 0; v < group.length; v++) {
                            projList.add(Projections.property(group[v]));
                        }
                    }
                    if (projList != null) {
                        c.setProjection(projList);
                    }

                    if (!c.list().isEmpty()) {
                        lista = (ArrayList) c.list();
                    } else {
                        return null;
                    }

                    if (!lista.isEmpty()) {
                        return lista;
                    }

                    break;
                }
            }

        } catch (Exception e) {
            session.close();
            JOptionPane.showMessageDialog(null, "Ocorreu o seguinte erro ao pesquisar os dados: " + e.getMessage(),
                    "Erro no pesquisar", 0);
        } finally {
            session.close();
        }

        return lista;
    }

    public int ultimoCodigo(String modelo, String campo) {
        SessionFactory sf = HibernateUtil.getSessionFactory();
        Session session = sf.openSession();

        Object ccc = null;
        String xxx = modelo.toString();
        try {
            try {
                ccc = Class.forName(modelo).newInstance();
            } catch (java.lang.InstantiationException | IllegalAccessException ex) {
                Logger.getLogger(SistemaDAO.class.getName()).log(Level.SEVERE, null, ex);
            }
        } catch (ClassNotFoundException ex) {
            Logger.getLogger(SistemaDAO.class.getName()).log(Level.SEVERE, null, ex);
        }

        ArrayList lista = null;

        Criteria c = session.createCriteria(ccc.getClass());
        ProjectionList projList = Projections.projectionList();
        projList = null;

        int maxId = (int) c.setProjection(Projections.max(campo)).uniqueResult();

        return maxId;
    }
}
